#ifndef _CU_UINT2_H_
#define _CU_UINT2_H_

//**********************************************************************************
// uint2 operators and functions
//**********************************************************************************

SDH_CALL uint2 operator + (const uint2 & u, uint v) { uint2 r = { u.x + v, u.y + v }; return r; }
SDH_CALL uint2 operator - (const uint2 & u, uint v) { uint2 r = { u.x - v, u.y - v }; return r; }
SDH_CALL uint2 operator * (const uint2 & u, uint v) { uint2 r = { u.x * v, u.y * v }; return r; }
SDH_CALL uint2 operator / (const uint2 & u, uint v) { uint2 r = { u.x / v, u.y / v }; return r; }

SDH_CALL uint2 operator + (uint v, const uint2 & u) { uint2 r = { v + u.x, v + u.y }; return r; }
SDH_CALL uint2 operator - (uint v, const uint2 & u) { uint2 r = { v - u.x, v - u.y }; return r; }
SDH_CALL uint2 operator * (uint v, const uint2 & u) { uint2 r = { v * u.x, v * u.y }; return r; }
SDH_CALL uint2 operator / (uint v, const uint2 & u) { uint2 r = { v / u.x, v / u.y }; return r; }

SDH_CALL uint2 operator + (const uint2 & u, const uint2 & v) { uint2 r = { u.x + v.x, u.y + v.y }; return r; }
SDH_CALL uint2 operator - (const uint2 & u, const uint2 & v) { uint2 r = { u.x - v.x, u.y - v.y }; return r; }
SDH_CALL uint2 operator * (const uint2 & u, const uint2 & v) { uint2 r = { u.x * v.x, u.y * v.y }; return r; }
SDH_CALL uint2 operator / (const uint2 & u, const uint2 & v) { uint2 r = { u.x / v.x, u.y / v.y }; return r; }

SDH_CALL uint2   operator - (const uint2 & v) { uint2 r = { -v.x, -v.y }; return r; }

SDH_CALL uint2 & operator += (uint2 & u, const uint2 & v) { u.x += v.x; u.y += v.y; return u; }
SDH_CALL uint2 & operator -= (uint2 & u, const uint2 & v) { u.x -= v.x; u.y -= v.y; return u; }
SDH_CALL uint2 & operator *= (uint2 & u, const uint2 & v) { u.x *= v.x; u.y *= v.y; return u; }
SDH_CALL uint2 & operator /= (uint2 & u, const uint2 & v) { u.x /= v.x; u.y /= v.y; return u; }

SDH_CALL uint2 & operator += (uint2 & u, uint v) { u.x += v; u.y += v; return u; }
SDH_CALL uint2 & operator -= (uint2 & u, uint v) { u.x -= v; u.y -= v; return u; }
SDH_CALL uint2 & operator *= (uint2 & u, uint v) { u.x *= v; u.y *= v; return u; }
SDH_CALL uint2 & operator /= (uint2 & u, uint v) { u.x /= v; u.y /= v; return u; }

SDH_CALL uint2 catmullrom (const uint2 & P0, const uint2 & P1, const uint2 & P2, const uint2 & P3, float t)
{
  const float ts = t * t;
  const float tc = t * ts;

  return (P0 * (-tc + 2.0f * ts - t) + P1 * (3.0f * tc - 5.0f * ts + 2.0f) + P2 * (-3.0f * tc + 4.0f * ts + t) + P3 * ( tc - ts)) * 0.5f;
}
SDH_CALL uint2 lerp      (const uint2 & u, const uint2 & v, float t ) { return u + t * (v - u); }
SDH_CALL uint  dot       (const uint2 & u, const uint2 & v) { return (u.x*v.x + u.y*v.y); }
SDH_CALL uint2 clamp     (const uint2 & u, uint a, uint b) { uint2 r = { clamp(u.x, a, b), clamp(u.y, a, b) }; return r; }

SDH_CALL uint2 saturate  (const uint2 & u) { return clamp(u, 0.0f, 1.0f); }

SDH_CALL uint2 min(const uint2 & u, const uint2 & v){ uint2 r = {min(u.x, v.x), min(u.y, v.y)}; return r; }
SDH_CALL uint2 max(const uint2 & u, const uint2 & v){ uint2 r = {max(u.x, v.x), max(u.y, v.y)}; return r; }

SDH_CALL uint  sad (const uint2 & u, const uint2 & v) { return (abs(u.x - v.x) + abs(u.y - v.y)); } // Sum of Absolute Differences for xy components
SDH_CALL uint  ssd (const uint2 & u, const uint2 & v) { return (sqr(u.x - v.x) + sqr(u.y - v.y)); } // Sum of Squared Differences for xy components

SDH_CALL uint2 set(uint2 & v, uint x = 0, uint y = 0) 
{ 
  v.x = x; v.y = y; return v; 
}
SDH_CALL uint2 set(uint2 & v, uint1 x, uint y = 0.0f) 
{ 
  v.x = x.x; v.y = y; return v; 
}

SDH_CALL uint2 ui2() { uint2 r = {0, 0}; return r;}
SDH_CALL uint2 ui2(uint x) { uint2 r = {x, x}; return r;}
SDH_CALL uint2 ui2(uint x, uint y) { uint2 r = {x, y}; return r;}
SDH_CALL uint2 ui2(const uint1 & u, uint y) { uint2 r = {u.x, y}; return r; }

SDH_CALL float  length (const uint2 & u) { return sqrtf(sqr(u.x) + sqr(u.y)); }

#endif